// import com.alibaba.druid.DbType;
// import com.alibaba.druid.sql.SQLUtils;
// import com.alibaba.druid.sql.ast.SQLExpr;
// import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
// import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
// import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
// import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
// import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
// import com.alibaba.druid.sql.dialect.oracle.ast.OracleSQLObject;
// import com.alibaba.druid.sql.dialect.oracle.ast.clause.ModelClause;
// import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

#include "OracleSelectQueryBlock.h"
#include "../../../../../DbType.h"
#include "../../../../SQLUtils.h"
#include "../../../../ast/SQLExpr.h"
#include "../../../../ast/SQLCommentHint.h"
#include "../../../../ast/expr/SQLBinaryOperator.h"
#include "../../../../ast/expr/SQLIdentifierExpr.h"
#include "../../../../ast/expr/SQLIntegerExpr.h"
#include "../../../../ast/statement/SQLExprTableSource.h"
#include "../clause/ModelClause.h"
#include "../../visitor/OracleASTVisitor.h"
#include "../../../../visitor/SQLASTVisitor.h"
#include "../../../../../utils/instanceof.h"
#include "../../../../../utils/listTran.h"
#include "../../../../../Exception/UnsupportedOperationException.h"
#include "OracleSelectTableReference.h"

SQLObject_ptr OracleSelectQueryBlock::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<OracleSelectQueryBlock>(new OracleSelectQueryBlock());
  std::shared_ptr<OracleSelectQueryBlock> x = std::dynamic_pointer_cast<OracleSelectQueryBlock>(clone_tmp);
  // OracleSelectQueryBlock x = new OracleSelectQueryBlock();

  SQLSelectQueryBlock::cloneTo(x);

  if (modelClause != nullptr)
  {
    x->setModelClause(std::dynamic_pointer_cast<ModelClause>(modelClause->clone()));
  }

  if (forUpdateOf != nullptr)
  {
    for (SQLExpr_ptr item : *forUpdateOf)
    {
      SQLExpr_ptr item1 = std::dynamic_pointer_cast<SQLExpr>(item->clone());
      item1->setParent(x);
      x->getForUpdateOf()->push_back(item1);
    }
  }

  x->skipLocked = skipLocked;

  return x;
}

OracleSelectQueryBlock::OracleSelectQueryBlock()
{
  dbType = DbType_ptr(new DbType(&DbType::oracle));
}

ModelClause_ptr OracleSelectQueryBlock::getModelClause()
{
  return modelClause;
}

void OracleSelectQueryBlock::setModelClause(ModelClause_ptr modelClause)
{
  this->modelClause = modelClause;
}

BOOL_ptr OracleSelectQueryBlock::isSkipLocked()
{
  return skipLocked;
}

void OracleSelectQueryBlock::setSkipLocked(BOOL_ptr skipLocked)
{
  this->skipLocked = skipLocked;
}

// @Override
void OracleSelectQueryBlock::accept0(SQLASTVisitor_ptr visitor)
{
  if (instanceof <SQLASTVisitor, OracleASTVisitor>(visitor))
  {
    accept0(std::dynamic_pointer_cast<OracleASTVisitor>(visitor));
    return;
  }

  SQLSelectQueryBlock::accept0(visitor);
}

void OracleSelectQueryBlock::accept0(OracleASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(OracleSelectQueryBlock)))
  {
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLCommentHint, SQLObject>(this->hints);
    acceptChild(visitor, tmp1);
    SQLObject_list_ptr tmp2 = ListTran::tran_class<SQLSelectItem, SQLObject>(this->selectList);
    acceptChild(visitor, tmp2);
    acceptChild(visitor, this->into);
    acceptChild(visitor, this->from);
    acceptChild(visitor, this->where);
    acceptChild(visitor, this->startWith);
    acceptChild(visitor, this->connectBy);
    acceptChild(visitor, this->groupBy);
    acceptChild(visitor, this->orderBy);
    acceptChild(visitor, this->waitTime);
    acceptChild(visitor, this->limit_);
    acceptChild(visitor, this->modelClause);
    SQLObject_list_ptr tmp3 = ListTran::tran_class<SQLExpr, SQLObject>(this->forUpdateOf);
    acceptChild(visitor, tmp3);
  }
  visitor->endVisit(SharedObject(OracleSelectQueryBlock));
}

string_ptr OracleSelectQueryBlock::toString()
{
  return SQLUtils::toOracleString(SharedObject(OracleSelectQueryBlock));
}

void OracleSelectQueryBlock::limit(int rowCount, int offset)
{
  if (offset <= 0)
  {
    SQLExpr_ptr rowCountExpr = SQLIntegerExpr_ptr(new SQLIntegerExpr(rowCount));
    SQLExpr_ptr newCondition = SQLUtils::buildCondition(SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BooleanAnd)), rowCountExpr, BOOL::FALSE, where);
    setWhere(newCondition);
  }
  else
  {
    throw new UnsupportedOperationException(make_string_ptr("not support offset"));
  }
}

void OracleSelectQueryBlock::setFrom(string_ptr tableName)
{
  SQLExprTableSource_ptr from;
  if (tableName == nullptr || tableName->length() == 0)
  {
    from = nullptr;
  }
  else
  {
    from = OracleSelectTableReference_ptr(new OracleSelectTableReference(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tableName))));
  }
  this->SQLSelectQueryBlock::setFrom(from);
}
